package com.yx.frame.http;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.json.JSONArray;
import org.json.JSONObject;

public class NioHttpClient {
	private static final String _pKey = "ShhOt0m5gfMpsLjP";
	private static char[] base64EncodeChars = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
			'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
			'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
			'2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
	private static final String BOUNDARY = "----WebKitFormBoundaryT1HoybnYeFOGFlBR";
	private static final Charset charset = Charset.forName("UTF8");
	private static String _host = "localhost";
	private static int _port = 8080;
	private static String _userName = "wukai";
	private static String _password = "111111";

	private final static String signUserRequest() throws Exception {
		long timestamp = System.currentTimeMillis();
		String md5Key = MD5(_password + timestamp);
		if (md5Key.length() > 16)
			md5Key = md5Key.substring(0, 16);
		String encrypted = AESEncrypt(String.valueOf(timestamp), md5Key);
		String signTxt = "[\"" + _userName + "\",\"" + encrypted + "\",\"" + timestamp + "\"]";
		String signEncrypted = AESEncrypt(signTxt, _pKey);
		return signEncrypted;
	}

	private static String MD5(String str) throws Exception {
		String encode = str;
		StringBuilder stringbuilder = new StringBuilder();
		MessageDigest md5 = MessageDigest.getInstance("MD5");
		md5.update(encode.getBytes("utf-8"));
		byte[] str_encoded = md5.digest();
		for (int i = 0; i < str_encoded.length; i++) {
			if ((str_encoded[i] & 0xff) < 0x10) {
				stringbuilder.append("0");
			}
			stringbuilder.append(Long.toString(str_encoded[i] & 0xff, 16));
		}
		return stringbuilder.toString();
	}

	private static String AESEncrypt(String sSrc, String sKey) throws Exception {
		if (sKey == null)
			return null;
		if (sKey.length() != 16)
			return null;
		byte[] raw = sKey.getBytes();
		SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
		Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		IvParameterSpec iv = new IvParameterSpec(sKey.getBytes());
		cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
		byte[] encrypted = cipher.doFinal(sSrc.getBytes());
		return encode(encrypted);
	}

	private static String encode(byte[] data) {
		StringBuffer sb = new StringBuffer();
		int len = data.length;
		int i = 0;
		int b1, b2, b3;
		while (i < len) {
			b1 = data[i++] & 0xff;
			if (i == len) {
				sb.append(base64EncodeChars[b1 >>> 2]);
				sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
				sb.append("==");
				break;
			}
			b2 = data[i++] & 0xff;
			if (i == len) {
				sb.append(base64EncodeChars[b1 >>> 2]);
				sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
				sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
				sb.append("=");
				break;
			}
			b3 = data[i++] & 0xff;
			sb.append(base64EncodeChars[b1 >>> 2]);
			sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
			sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
			sb.append(base64EncodeChars[b3 & 0x3f]);
		}
		return sb.toString();
	}

	public final static void setServerUrl(String url) throws Exception {
		URL aURL = new URL(url);
		_host = aURL.getHost();
		_port = aURL.getPort();
	}
	public final static InputStream fileDownload(String fileName)throws Exception {
		URL myFileURL;
		String url="http://"+_host+":"+_port+"/Download?UId="+URLEncoder.encode(signUserRequest(), "UTF-8")+"&File="+fileName;
        myFileURL = new URL(url);  
        HttpURLConnection conn=(HttpURLConnection)myFileURL.openConnection();  
        conn.setConnectTimeout(6000);  
        conn.setDoInput(true);  
        conn.setUseCaches(false);           
        return conn.getInputStream();
	}

	public final static String fileUpload(File file) throws Exception {
		FileInputStream fis = null;
		FileChannel fileChannel = null;
		SocketChannel channel = null;
		try {
			StringBuilder sb = new StringBuilder();
			sb.append("--" + BOUNDARY + "\r\n");
			sb.append("Content-Disposition: form-data; name=\"UId\"\r\n");
			sb.append("\r\n");
			sb.append(signUserRequest() + "\r\n");
			sb.append("--" + BOUNDARY + "\r\n");
			sb.append("Content-Disposition: form-data; name=\"file1\"; filename=\"" + file.getName() + "\"" + "\r\n");
			sb.append("Content-Type: image/jpeg" + "\r\n");
			sb.append("\r\n");
			String headerInfo = sb.toString();
			String endInfo = "\r\n--" + BOUNDARY + "--\r\n";
			channel = SocketChannel.open(new InetSocketAddress(_host, _port));
			StringBuffer request = new StringBuffer();
			request.append("POST /FileUpload HTTP/1.1\r\n");
			request.append("Cache-Control: no-cache\r\n");
			request.append("Pragma: no-cache\r\n");
			request.append("User-Agent: JavaSocket/").append(System.getProperty("java.version")).append("\r\n");
			request.append("Host: ").append(_host).append("\r\n");
			request.append("Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n");
			request.append("Connection: keep-alive\r\n");
			request.append("Content-Type: multipart/form-data; boundary=" + BOUNDARY + "\r\n");
			request.append("Content-Length: "
					+ (headerInfo.getBytes().length + file.length() + endInfo.getBytes().length) + "\r\n");
			request.append("\r\n");
			channel.write(charset.encode(request.toString()));
			channel.write(charset.encode(headerInfo));
			fis = new FileInputStream(file);
			fileChannel = fis.getChannel();
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			while (fileChannel.read(buffer) != -1) {
				buffer.flip();
				channel.write(buffer);
				buffer.clear();
			}
			channel.write(charset.encode(endInfo));
			channel.socket().shutdownOutput();
			int size = -1;
			buffer.clear();
			CharsetDecoder decoder = charset.newDecoder();
			StringBuffer retStr = new StringBuffer();
			while ((size = channel.read(buffer)) != -1) {
				buffer.flip();
				CharBuffer charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
				retStr.append(charBuffer.toString());
				buffer.clear();
			}			
			String jsonRetStr = retStr.toString();
			jsonRetStr = jsonRetStr.substring(jsonRetStr.indexOf("{"), jsonRetStr.length() - 9);
			JSONObject returnObj = new JSONObject(jsonRetStr);
			if (!returnObj.getBoolean("IsOK")) {
				throw new Exception(returnObj.getString("Message"));
			}
			return getUploadedFileUrl(returnObj);
		} finally {
			try {
				channel.close();
			} catch (Exception e) {
			}
			try {
				fileChannel.close();
			} catch (Exception e) {
			}
			try {
				fis.close();
			} catch (Exception e) {
			}
		}
	}

	public final static JSONObject post(int actionId, boolean asyncService, JSONObject data) throws Exception {
		SocketChannel channel = null;
		try {
			JSONObject requestData = new JSONObject();
			requestData.put("ActionId", actionId);
			requestData.put("UId", signUserRequest());
			requestData.put("AsyncService", asyncService);
			requestData.put("RequestData", data);
			String message = requestData.toString();
			message  = URLEncoder.encode(message, "UTF-8");
			channel = SocketChannel.open(new InetSocketAddress(_host, _port));
			StringBuffer request = new StringBuffer();
			request.append("POST /JsonRemote HTTP/1.1\r\n");
			request.append("Cache-Control: no-cache\r\n");
			request.append("Pragma: no-cache\r\n");
			request.append("User-Agent: JavaSocket/").append(System.getProperty("java.version")).append("\r\n");
			request.append("Host: ").append(_host).append("\r\n");
			request.append("Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n");
			request.append("Connection: keep-alive\r\n");
			request.append("Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n");
			request.append("Content-Length: " + message.getBytes().length + "\r\n");
			request.append("\r\n");
			channel.write(charset.encode(request.toString()));
			channel.write(charset.encode(message));
			channel.socket().shutdownOutput();
			int size = -1;
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			byte[] allReadArray=new byte[0];
			while ((size = channel.read(buffer)) != -1) {
				buffer.flip();
				ByteBuffer readOnlyBufffer=buffer.asReadOnlyBuffer();
				byte[] newArray=new byte[allReadArray.length+size];
				System.arraycopy(allReadArray, 0, newArray, 0, allReadArray.length);
				for(int i=allReadArray.length;i<newArray.length;i++){
					newArray[i]=readOnlyBufffer.get();
				}
				allReadArray=newArray;
				buffer.clear();
			}
			CharBuffer charBuffer = charset.decode(ByteBuffer.wrap(allReadArray));
			String jsonRetStr = charBuffer.toString();
			jsonRetStr = jsonRetStr.substring(jsonRetStr.indexOf("{"), jsonRetStr.length() - 9);
			JSONObject returnObj = new JSONObject(jsonRetStr);
			if (!returnObj.getBoolean("IsOK")) {
				throw new Exception(returnObj.getString("Message"));
			}
			return returnObj;
		} finally {
			try {
				channel.close();
			} catch (Exception e) {
			}			
		}
	}

	protected static final List<int[]> getUpdateResult(JSONObject serviceResult) throws Exception {
		List<int[]> result = new ArrayList<int[]>();
		JSONArray jArray = serviceResult.getJSONArray("Result");
		int row = jArray.length();
		for (int i = 0; i < row; i++) {
			JSONArray rowArray = jArray.getJSONArray(i);
			int col = rowArray.length();
			int[] colData = new int[col];
			for (int j = 0; i < col; j++) {
				colData[j] = rowArray.getInt(j);
			}
			result.add(colData);
		}
		return result;
	}

	private static final String getUploadedFileUrl(JSONObject serviceResult) throws Exception {
		String fileUrl = null;
		JSONArray jArray = serviceResult.getJSONArray("FileUrl");
		if (jArray.length() > 0) {
			fileUrl = jArray.getString(0);
		}
		return fileUrl;
	}

	public static final void setUser(String userName, String password) {
		_userName = userName;
		_password = password;
	}

	public static void main(String[] args) {
		try {
			long t = System.currentTimeMillis();			
			//System.out.println(post(0, true, new JSONObject()));
			//System.out.println(fileUpload(new File("e:/IMG_1.JPG")));
			System.out.println("---" + (System.currentTimeMillis() - t));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
